// ActionScript file

	import org.httpclient.*;
	import org.httpclient.events.*;
	import com.adobe.net.URI;
	import com.adobe.utils.ArrayUtil;
	import mx.utils.URLUtil;
	import mx.modules.*;
	import mx.managers.PopUpManager;
	import mx.collections.ArrayCollection;
	import mx.events.ModuleEvent;
	import modules.*;
	import flash.net.SharedObject;
	import mx.events.FlexEvent;
	import flash.utils.getTimer;
	import utils.Formatters;
	import flash.events.MouseEvent;
	import mx.utils.ObjectUtil;
	import flash.events.KeyboardEvent;
	import com.hurlant.util.Hex;
	import org.httpclient.http.Get;
	import org.httpclient.http.Post;
	import org.httpclient.http.Put;
	import org.httpclient.http.Delete;
	import spark.events.TextOperationEvent;
	import spark.events.IndexChangeEvent;
	import org.iotashan.oauth.*;
	import flash.net.URLRequestHeader;
	import flash.utils.ByteArray;

	[Bindable] public var params:ArrayCollection = new ArrayCollection();
	[Bindable] public var headers:ArrayCollection = new ArrayCollection();
	[Bindable] public var requests:ArrayCollection = new ArrayCollection();
	[Bindable] public var http_baseurls:ArrayCollection = new ArrayCollection();
	[Bindable] public var http_resources:ArrayCollection = new ArrayCollection();
	[Bindable] public var param_templates:ArrayCollection = new ArrayCollection();
	[Bindable] public var header_templates:ArrayCollection = new ArrayCollection();
	[Bindable] public var _consumer_key:String = '';
	[Bindable] public var _consumer_secret:String = '';
	[Bindable] public var _rsa_privkey:String = '';

	private var http_service:HttpClient = new HttpClient(),
				so:SharedObject,
				starttime:int,
				cancelled:Boolean;

	protected function onComplete(event:FlexEvent):void
	{
		trace('init');
		so = SharedObject.getLocal("REST_API_Test");
		if (so.data.http_baseurls) {
			http_baseurls = so.data.http_baseurls;
			http_baseurls.refresh();
		}
		if (so.data.http_resources) {
			http_resources = so.data.http_resources;
			http_resources.refresh();
		}
		if (so.data.param_templates) {
			param_templates = so.data.param_templates;
			param_templates.refresh();
		}
		if (so.data.consumer_key) {
			_consumer_key = so.data.consumer_key;
		}
		if (so.data.consumer_secret) {
			_consumer_secret = so.data.consumer_secret;
		}
		if (so.data.rsa_privkey) {
			_rsa_privkey = so.data.rsa_privkey;
		}
		http_service.listener.onClose = onClose;
		http_service.listener.onError = onError;
		http_service.listener.onComplete = onResponse;
		http_service.listener.onData = onData;
		http_service.listener.onRequest = onRequest;
	}

	protected function httpLabel(item:Object):String
	{
		return item.action+' ('+item.name+')';
	}
	
	protected function onSend(event:MouseEvent):void
	{
		var arr:Array = new Array(),
			url:String = '',
			uri:URI,
			req_get:Get = new Get(),
			req_post:Post = new Post(),
			req_put:Put = new Put(),
			req_del:Delete = new Delete(),
			s:String = '',
			h:URLRequestHeader,
			ba:ByteArray = new ByteArray(),
			sig:*,
			obj:Object = new Object(),
			signed:Boolean = false;
		
		if (http_baseurl.textInput.text.length < 4) {
			http_baseurl.textInput.errorString = 'Required field';
			return;
		}
		url = String(http_baseurl.textInput.text).replace(new RegExp('/$'), '') + '/' + String(http_resource.textInput.text).replace(new RegExp('/$'), '');
		uri = new URI(url);
		for each (var item:Object in params) {
			arr.push({'name':item.key, 'value':item.val});
			obj[item.key] = item.val;
		}
		if (btn_sign)
			signed = btn_sign.selected;
		if (signed) {
			var cons:OAuthConsumer = new OAuthConsumer(consumer_key.text, consumer_secret.text);
			var req:OAuthRequest = new OAuthRequest(http_method.selectedItem.name, uri.toString(), obj, cons);
			if (oauth_method)
				switch (oauth_methods[oauth_method.selectedIndex].short) {
					case 'plain':
						sig = new OAuthSignatureMethod_PLAINTEXT();
						break;
					case 'rsa':
						sig = new OAuthSignatureMethod_RSA_SHA1();
						req.consumer.secret = rsa_privkey.text;
						break;
					default:
						sig = new OAuthSignatureMethod_HMAC_SHA1();
						break;
				}
			req.buildRequest(sig);
			h = req.getRequestResult(OAuthRequest.RESULT_TYPE_HEADER, 'auth');
		}
		switch (http_method.selectedItem.name) {
			case 'GET':
				for each (item in params) {
					uri.setQueryValue(item.key, item.val);
				}
				for each (item in headers) {
					req_get.addHeader(item.key, item.val);
				}
				if (signed) {
					req_get.addHeader(h.name, h.value);
					uri.queryRaw = req.getRequestResult(OAuthRequest.RESULT_TYPE_POST, 'auth');
					http_service.request(uri, req_get);
				} else
					http_service.request(uri, req_get);
				break;
			case 'POST':
				if (signed) {
					req_post.header.replace("Content-Type", "application/x-www-form-urlencoded");
					ba.writeUTFBytes(req.getRequestResult(OAuthRequest.RESULT_TYPE_POST, 'auth'));
					ba.position = 0;
					req_post.body = ba;
				} else
					req_post.setFormData(arr);
				for each (item in headers) {
					req_post.addHeader(item.key, item.val);
				}
				if (signed)
					req_post.addHeader(h.name, h.value);
				http_service.request(uri, req_post);
				break;
			case 'PUT':
				if (signed) {
					req_put.header.replace("Content-Type", "application/x-www-form-urlencoded");
					ba.writeUTFBytes(req.getRequestResult(OAuthRequest.RESULT_TYPE_POST, 'auth'));
					ba.position = 0;
					req_put.body = ba;
				} else
					req_put.setFormData(arr);
				for each (item in headers) {
					req_put.addHeader(item.key, item.val);
				}
				if (signed)
					req_put.addHeader(h.name, h.value);
				http_service.request(uri, req_put);
				break;
			case 'DELETE':
				for each (item in params) {
					uri.setQueryValue(item.key, item.val);
				}
				for each (item in headers) {
					req_del.addHeader(item.key, item.val);
				}
				if (signed) {
					req_del.addHeader(h.name, h.value);
					uri.queryRaw = req.getRequestResult(OAuthRequest.RESULT_TYPE_POST, 'auth');
					http_service.request(uri, req_del);
				} else
					http_service.request(uri, req_del);
				break;
		}
		btn_send.enabled = false;
		cancelled = false;
		obj={};
		obj.url = url;
		obj.method = http_method.selectedItem.name;
		obj.parameters = new ArrayCollection(ObjectUtil.copy(params.source) as Array);
		requests.addItem(obj);
		starttime = getTimer();
	}

	protected function onCancel(event:MouseEvent):void {
		cancelled = true;
		http_service.cancel();
	}

	protected function onRequest(event:HttpRequestEvent):void
	{
		trace(event.toString());
	}

	protected function onResponse(event:HttpResponseEvent):void
	{
		var resp:HttpResponse,
			idx:int,
			obj:Object;
		resp = event.response;
//		trace(resp.code, resp.contentLength, resp.message, event.toString(), resp.header);
		idx = requests.length-1;
		obj = requests.getItemAt(idx);
		obj.code = resp.code;
		obj.time = Formatters.formatTime(getTimer() - starttime);
		if (resp.contentLength>-1) {
			obj.size = Formatters.formatSize(resp.contentLength);
			obj.sizeB = resp.contentLength;
		}
		obj.status = 'Done';
		obj.contenttype = resp.header.getValue("Content-Type");
		obj.responseline = 'HTTP/'+ resp.version + ' ' + resp.code + ' ' + resp.message;
		obj.headers = new ArrayCollection();
		for each (var o:Object in resp.header._headers) {
			(obj.headers as ArrayCollection).addItem({key:o.name, val:o.value});
		}
		requests.setItemAt(obj, idx);
		btn_send.enabled = true;
	}
	
	protected function onError(event:ErrorEvent):void
	{
		trace(event.toString());
		var obj:Object,
			idx:int;
		btn_send.enabled = true;
		idx = requests.length-1;
		obj = requests.getItemAt(idx);
		obj.time = Formatters.formatTime(getTimer() - starttime);
		obj.status = 'Error';
		requests.setItemAt(obj, idx);
	}

	protected function onClose(event:Event):void
	{
		var obj:Object,
			idx:int;
		trace(event.toString());
		btn_send.enabled = true;
		if (cancelled) {
			idx = requests.length-1;
			obj = requests.getItemAt(idx);
			obj.time = Formatters.formatTime(getTimer() - starttime);
			obj.status = 'Cancelled';
			requests.setItemAt(obj, idx);
		}
	}

	protected function onData(event:HttpDataEvent):void
	{
		var obj:Object,
			idx:int;
		idx = requests.length-1;
		obj = requests.getItemAt(idx);
		obj.response = event.readUTFBytes();
		if (obj.size==null) {
			obj.size = Formatters.formatSize(event.bytes.length);
			obj.sizeB = event.bytes.length;
		}
		obj.responsehex = Hex.fromArray(event.bytes, true); 
		requests.setItemAt(obj, idx);
		btn_send.enabled = true;
	}

	protected function onParamAdd(event:MouseEvent):void
	{
		params.addItem({key:'', val:''});
		http_params.editedItemPosition = {rowIndex:params.length-1, columnIndex:0};
	}
	
	protected function onParamDel(event:MouseEvent):void
	{
		params.removeItemAt(http_params.selectedIndex);
	}
	
	protected function onParamClear(event:MouseEvent):void
	{
		params.removeAll();
	}
	
	protected function onHeaderAdd(event:MouseEvent):void
	{
		headers.addItem({key:'', val:''});
		http_headers.editedItemPosition = {rowIndex:headers.length-1, columnIndex:0};
	}
	
	protected function onHeaderDel(event:MouseEvent):void
	{
		headers.removeItemAt(http_headers.selectedIndex);
	}
	
	protected function onHeaderClear(event:MouseEvent):void
	{
		headers.removeAll();
	}
	
	protected function onResourceAdd(event:MouseEvent):void
	{
		var win:AddSimpleText = new AddSimpleText(),
			addif:AddSimpleTextIF;
		addif = win;
		addif.setTitle('Add Resource');
		addif.setFormLabel('Resource name');
		addif.setCallback(this.AddResource);
		PopUpManager.addPopUp(win, this, true);
	}
	
	public function AddResource(name:String):void {
		http_resources.addItem({name:name});
		http_resources.refresh()
		so.data.http_resources = http_resources;
	}
	
	protected function onResourceDel(event:MouseEvent):void
	{
		http_resources.removeItemAt(http_resource.selectedIndex);
		http_resources.refresh();
		so.data.http_resources = http_resources;
	}

	protected function onClear(event:MouseEvent):void {
		requests.removeAll();
		requests.refresh();
	}

	protected function onRemove(event:MouseEvent):void {
		requests.removeItemAt(http_requests.selectedIndex);
		requests.refresh();
	}

	protected function popDetail(event:MouseEvent):void {
		var win:DetailPopup = new DetailPopup(),
			detif:DetailPopupIF;
		detif = win;
		detif.setItems(requests.getItemAt(http_requests.selectedIndex));
		PopUpManager.addPopUp(win, this, true);
	}

	protected function popEditBaseURL(event:MouseEvent):void {
		var win:EditList = new EditList(),
			ifc:EditListIF;
		ifc = win;
		ifc.setTitle('Edit BaseURLs');
		ifc.setLabelField('name');
		ifc.setArr(http_baseurls);
		ifc.setCallback(this.onSetBaseURL);
		PopUpManager.addPopUp(win, this, true);
	}

	public function onSetBaseURL(arr:ArrayCollection):void {
		http_baseurls = new ArrayCollection(ObjectUtil.copy(arr.source) as Array);
		so.data.http_baseurls = http_baseurls;
	}

	protected function http_baseurl_creationCompleteHandler(event:FlexEvent):void
	{
		http_baseurl.textInput.addEventListener(FlexEvent.ENTER, onBaseURLEnter);
	}

	protected function onBaseURLEnter(event:FlexEvent):void
	{
		if (http_baseurl.textInput.text.length == 0)
			return;
		var match:Boolean = false;
		for each (var obj:Object in http_baseurls) {
			if (obj.name == http_baseurl.textInput.text) {
				match = true;
				break;
			}
		}
		if (!match) {
			http_baseurls.addItem({name:http_baseurl.textInput.text});
			so.data.http_baseurls = http_baseurls;
		}
	}

	protected function popEditResource(event:MouseEvent):void {
		var win:EditList = new EditList(),
			ifc:EditListIF;
		ifc = win;
		ifc.setTitle('Edit Resources');
		ifc.setLabelField('name');
		ifc.setArr(http_resources);
		ifc.setCallback(this.onSetResource);
		PopUpManager.addPopUp(win, this, true);
	}

	public function onSetResource(arr:ArrayCollection):void {
		http_resources = new ArrayCollection(ObjectUtil.copy(arr.source) as Array);
		so.data.http_resources = http_resources;
	}

	protected function http_resource_creationCompleteHandler(event:FlexEvent):void
	{
		http_resource.textInput.addEventListener(FlexEvent.ENTER, onResourceEnter);
	}

	protected function onResourceEnter(event:FlexEvent):void
	{
		if (http_resource.textInput.text.length == 0)
			return;
		var match:Boolean = false;
		for each (var obj:Object in http_resources) {
			if (obj.name == http_resource.textInput.text) {
				match = true;
				break;
			}
		}
		if (!match) {
			http_resources.addItem({name:http_resource.textInput.text});
			so.data.http_resources = http_resources;
		}
	}

	protected function popSaveParams(event:MouseEvent):void
	{
		var win:SavePopup = new SavePopup(),
			ifc:SavePopupIF;
		ifc = win;
		ifc.setTitle('Save Parameters to template');
		ifc.setLabel('Template name');
		ifc.setCallback(this.onSaveParams);
		PopUpManager.addPopUp(win, this, true);
	}

	public function onSaveParams(s:String):void {
		var match_idx:int = -1,
			i:int,
			o:Object;
		for (i=0; i<param_templates.length; i++) {
			o = param_templates.getItemAt(i);
			if (o.name == s) {
				match_idx = i;
				break;
			}
		}
		if (match_idx > -1) {
			o.arr = new ArrayCollection(ObjectUtil.copy(params.source) as Array);
			param_templates.setItemAt(o, match_idx);
		} else {
			o = {name:s, arr:new ArrayCollection(ObjectUtil.copy(params.source) as Array)}; 
			param_templates.addItem(o);
		}
		so.data.param_templates = param_templates;				
	}
	
	protected function popLoadParams(event:MouseEvent):void
	{
		var win:LoadPopup = new LoadPopup(),
			ifc:LoadPopupIF;
		ifc = win;
		ifc.setTitle('Load Parameters from template');
		ifc.setLabelField('name');
		ifc.setArr(param_templates);
		ifc.setCallback(this.onLoadParams);
		PopUpManager.addPopUp(win, this, true);
	}

	public function onLoadParams(s:String, save:Boolean=false, arr:ArrayCollection=null):void {
		if (save) {
			param_templates = new ArrayCollection(ObjectUtil.copy(arr.source) as Array);
			so.data.param_templates = param_templates;				
		}
		for each (var o:Object in param_templates) {
			if (o.name == s)
				params = new ArrayCollection(ObjectUtil.copy(o.arr.source) as Array);
		}
		params.refresh();
	}

	protected function popSaveHeaders(event:MouseEvent):void
	{
		var win:SavePopup = new SavePopup(),
			ifc:SavePopupIF;
		ifc = win;
		ifc.setTitle('Save Headers to template');
		ifc.setLabel('Template name');
		ifc.setCallback(this.onSaveHeaders);
		PopUpManager.addPopUp(win, this, true);
	}
	
	public function onSaveHeaders(s:String):void {
		var match_idx:int = -1,
			i:int,
			o:Object;
		for (i=0; i<header_templates.length; i++) {
			o = header_templates.getItemAt(i);
			if (o.name == s) {
				match_idx = i;
				break;
			}
		}
		if (match_idx > -1) {
			o.arr = new ArrayCollection(ObjectUtil.copy(headers.source) as Array);
			header_templates.setItemAt(o, match_idx);
		} else {
			o = {name:s, arr:new ArrayCollection(ObjectUtil.copy(headers.source) as Array)}; 
			header_templates.addItem(o);
		}
		so.data.header_templates = header_templates;				
	}
	
	protected function popLoadHeaders(event:MouseEvent):void
	{
		var win:LoadPopup = new LoadPopup(),
			ifc:LoadPopupIF;
		ifc = win;
		ifc.setTitle('Load Headers from template');
		ifc.setLabelField('name');
		ifc.setArr(header_templates);
		ifc.setCallback(this.onLoadHeaders);
		PopUpManager.addPopUp(win, this, true);
	}
	
	public function onLoadHeaders(s:String, save:Boolean=false, arr:ArrayCollection=null):void {
		if (save) {
			header_templates = new ArrayCollection(ObjectUtil.copy(arr.source) as Array);
			so.data.header_templates = header_templates;				
		}
		for each (var o:Object in header_templates) {
			if (o.name == s)
				headers = new ArrayCollection(ObjectUtil.copy(o.arr.source) as Array);
		}
		headers.refresh();
	}

	protected function oauth_method_changeHandler(event:IndexChangeEvent):void
	{
		formitem_secret.includeInLayout = formitem_secret.visible = oauth_method.selectedItem.short != 'rsa';
		formitem_rsa.includeInLayout = formitem_rsa.visible = !formitem_secret.visible;
	}
	
	
	protected function consumer_key_changeHandler(event:TextOperationEvent):void
	{
		so.data.consumer_key = consumer_key.text;
	}
	
	
	protected function consumer_secret_changeHandler(event:TextOperationEvent):void
	{
		so.data.consumer_secret = consumer_secret.text;
	}

	protected function consumer_key_creationCompleteHandler(event:FlexEvent):void
	{
		consumer_key.text = _consumer_key;
		consumer_key.validateNow();
	}
	
	
	protected function consumer_secret_creationCompleteHandler(event:FlexEvent):void
	{
		consumer_secret.text = _consumer_secret;
		consumer_secret.validateNow();
	}

	protected function rsa_privkey_changeHandler(event:TextOperationEvent):void
	{
		so.data.rsa_privkey = rsa_privkey.text; 
	}
	
	
	protected function rsa_privkey_creationCompleteHandler(event:FlexEvent):void
	{
		rsa_privkey.text = _rsa_privkey;
		rsa_privkey.validateNow();
	}
